﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

using DnPakExplorer.Forms;
using DnPakExplorer.Controls;

namespace DnPakExplorer {
	public partial class DntExplorer : FormBase {
		Color mErrorColor = Color.FromArgb(255, 200, 200);

		Dntable mDntable;
		DntAdapter mDntAdapter;
		DntableSearchForm mSearchForm;
		string mName;
		Hashtable mUnionedFileHeaders;

		public DntExplorer() {
			InitializeComponent();
			SetStyle(ControlStyles.ResizeRedraw, true);
			mListGridView.SetColumnHeaderHeight(40);
			menuStrip1.Renderer = new ContextMenuStripRenderer();
		}

		public void LoadDnt(string filename) {
			FileStream file = new FileStream(filename, FileMode.Open);
			LoadDnt(file, filename);
			file.Close();
		}

		public void LoadDnt(Stream stream, string name) {
			mDntable = new Dntable();
			mDntable.Load(stream);
			mDntAdapter = new DntAdapter(mDntable);
			mListGridView.SetAdapter(mDntAdapter);
			comboBox1.Items.Clear();
			comboBox1.Items.Add("_Key");
			for (int i=0; i<mDntable.FieldCount; i++) {
				comboBox1.Items.Add(mDntable.GetField(i).name);
			}
			mName = name;
			this.Text = name+" - "+mDntable.RecordCount;
		}

		public void LoadDnt(FileHeader fh, string name) {
			mUnionedFileHeaders = new Hashtable();
			mUnionedFileHeaders[fh] = fh;
			using (Stream stream = Util.GetExplorer().GetFileStream(fh)) {
				mDntable = new Dntable();
				mDntable.Load(stream);
				mDntAdapter = new DntAdapter(mDntable);
				mListGridView.SetAdapter(mDntAdapter);
				comboBox1.Items.Clear();
				comboBox1.Items.Add("_Key");
				for (int i = 0; i < mDntable.FieldCount; i++) {
					comboBox1.Items.Add(mDntable.GetField(i).name);
				}
			}
			mName = name;
			this.Text = name+" - "+mDntable.RecordCount;
		}

		int lastSearchedIndex = -1;
		public void Search(string text, int column) {
			int start = lastSearchedIndex + 1;
			column--;
			Grid g = new Grid();
			if (column!=-1) {
				for (int i=lastSearchedIndex + 1; i<mDntAdapter.RowCount; i++) {
					mDntAdapter.GetGridData(i, column, g);
					if (g.text.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) {
						lastSearchedIndex = i;
						mListGridView.Select(column, i, column, i);
						mListGridView.BringToVisible(i, column);
						return;
					}
				}
				for (int i=0; i<lastSearchedIndex; i++) {
					mDntAdapter.GetGridData(i, column, g);
					if (g.text.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) {
						lastSearchedIndex = i;
						mListGridView.Select(column, i, column, i);
						mListGridView.BringToVisible(i, column);
						return;
					}
				}
			} else {
				for (int i=lastSearchedIndex + 1; i<mDntAdapter.RowCount; i++) {
					mDntAdapter.GetRowHeader(i, g);
					if (g.text.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) {
						lastSearchedIndex = i;
						mListGridView.Select(0, i, mDntable.FieldCount-1, i);
						mListGridView.BringToVisible(i);
						return;
					}
				}
				for (int i=0; i<lastSearchedIndex; i++) {
					mDntAdapter.GetRowHeader(i, g);
					if (g.text.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) {
						lastSearchedIndex = i;
						mListGridView.Select(0, i, mDntable.FieldCount-1, i);
						mListGridView.BringToVisible(i);
						return;
					}
				}
			}
		}

		private void NntExplorer_Load(object sender, EventArgs e) {
		}

		private void OnSizeChanged(object sender, EventArgs e) {
			mListGridView.Size = new Size(ClientSize.Width-mListGridView.Location.X-12, ClientSize.Height-mListGridView.Location.Y-12);
			splitContainer1.Width = ClientSize.Width-mListGridView.Location.X-12;
		}

		private void OnMenuOpen(object sender, EventArgs e) {
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.CheckFileExists = true;
			dlg.Multiselect = false;
			dlg.Filter = "*dnt|*dnt";
			if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
				LoadDnt(dlg.FileName);
			}
		}

		private void DntExplorer_FormClosed(object sender, FormClosedEventArgs e) {
			mListGridView.Clear();
			mDntable.Clear();
		}

		private void OnMenuSearch(object sender, EventArgs e) {
			if (mSearchForm == null || mSearchForm.IsDisposed) {
				mSearchForm = new DntableSearchForm(this);
				mSearchForm.StartPosition = FormStartPosition.CenterScreen;
				mSearchForm.TopMost = true;
				string[] cols = new string[mDntAdapter.ColumnCount+1];
				cols[0] = "_Key";
				Grid g = new Grid();
				for (int i=0; i<mDntAdapter.ColumnCount; i++) {
					mDntAdapter.GetColumnHeader(i, g);
					cols[i+1] = g.text;
				}
				mSearchForm.SetCollumns(cols, 1);
				mSearchForm.Show(this);
			}
		}

		private void mListGridView_MouseClick(object sender, MouseEventArgs e) {
			if (e.Button == System.Windows.Forms.MouseButtons.Right) {
				Point pointIndex = mListGridView.PointToCellIndex(e.Location);
				if (pointIndex.X >= -1 && pointIndex.Y >= -1) {
					ContextMenuStrip menu = new ContextMenuStrip();
					menu.Items.Add("复制", null, OnContextMenu).Tag = pointIndex;
					if (pointIndex.Y == -1 && pointIndex.X>-1
						&& mDntable.GetField(pointIndex.X).type == DntFieldType.Int32
						) {
						if (!mDntAdapter.showAsUIString[pointIndex.X]
							&& !mDntable.GetField(pointIndex.X).uistring
							&& !mDntable.GetField(pointIndex.X).uiparams) {
							menu.Items.Add("显示为UIString", null, OnContextMenu).Tag = pointIndex;
						} else
							menu.Items.Add("取消显示为UIString", null, OnContextMenu).Tag = pointIndex;
					}
					menu.Show(Cursor.Position);
				}
			}
		}

		private void OnContextMenu(object sender, EventArgs e) {
			ToolStripItem item = (ToolStripItem)sender;
			if (item.Text == "复制") {
				ListGridView.SelectRect rect = mListGridView.GetSelected();
				StringBuilder sb = new StringBuilder();
				Grid grid = new Grid();
				for (int r=rect.top; r<=rect.bottom; r++) {
					if (r != rect.top)
						sb.Append('\n');
					for (int c=rect.left; c<=rect.right; c++) {
						mDntAdapter.GetGridData(r, c, grid);
						if (c != rect.left)
							sb.Append('\t');
						sb.Append(grid.text);
					}
				}
				if (sb.Length>0)
					Clipboard.SetDataObject(sb.ToString(), true);
			} else if (item.Text == "显示为UIString") {
				Point pointIndex = (Point)item.Tag;
				mDntAdapter.showAsUIString[pointIndex.X] = true;
				mListGridView.Refresh();
			} else if (item.Text == "取消显示为UIString") {
				Point pointIndex = (Point)item.Tag;
				mDntAdapter.showAsUIString[pointIndex.X] = false;
				mDntable.GetField(pointIndex.X).uiparams = false;
				mDntable.GetField(pointIndex.X).uistring = false;
				mListGridView.Refresh();
			}
		}


		private class FieldsInfo {

		}

		private class FieldInfo {
			public bool showAsUIString = true;
		}

		private void DntExplorer_Paint(object sender, PaintEventArgs e) {
		}

		private void textBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
			if (e.KeyCode == Keys.Enter && comboBox1.SelectedIndex>=0) {
				mDntAdapter.SetFilter(textBox1.Text, comboBox1.SelectedIndex-1, checkBox1.Checked);
				mListGridView.SetAdapter(mDntAdapter);
				mListGridView.Refresh();
			}
		}

		private void OnMenuUnion(object sender, EventArgs e) {
			if (mUnionedFileHeaders != null) {
				DntableUnionSeleteForm form = new DntableUnionSeleteForm(mUnionedFileHeaders, mDntable.GetFields());
				if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
					List<Dntable> tables = new List<Dntable>();
					foreach (FileHeader header in form.selectedFileHeaders) {
						using (Stream s = Util.GetExplorer().GetFileStream(header)) {
							Dntable table = new Dntable();
							table.Load(s);
							tables.Add(table);
						}
					}
					if (tables.Count > 0) {
						tables.Insert(0, mDntable);
						Dntable newTable = Dntable.UnionWith(tables);
						DntAdapter newAdapter = new DntAdapter(newTable);
						newAdapter.showAsUIString = mDntAdapter.showAsUIString;
						newAdapter.SetFilter(null, 0, false);
						mListGridView.SetAdapter(mDntAdapter = newAdapter);
						this.Text = mName+"(联合表) - "+newTable.RecordCount;
						mListGridView.Refresh();
						foreach (FileHeader header in form.selectedFileHeaders) {
							mUnionedFileHeaders[header] = header;
						}
					}
				}
			}
		}
	}


	public class DntAdapter : ListGridAdapter {

		public bool[] showAsUIString;
		Dntable mDnt = new Dntable();
		int[] mFiltedItems;

		public DntAdapter(Dntable dntable) {
			mDnt = dntable;
			showAsUIString = new bool[mDnt.FieldCount];
		}

		public void SetFilter(string filter, int column, bool regax) {
			if (String.IsNullOrEmpty(filter)) {
				mFiltedItems = null;
				return;
			}
		
			Grid g = new Grid();
			List<int> items = new List<int>();
			if (regax) {
				Regex pettern = new Regex(filter);
				if (column >= 0) {
					for (int r = 0; r < mDnt.RecordCount; r++) {
						GetGridDataNoFilted(r, column, g);
						if (g.text != null && pettern.IsMatch(g.text)) {
							items.Add(r);
						}
					}
				} else if (column == -1) {
					try {
						int value = int.Parse(filter);
						for (int r = 0; r < mDnt.RecordCount; r++) {
							if (pettern.IsMatch(mDnt.GetKey(r).ToString())) {
								items.Add(r);
							}
						}
					} catch (FormatException) {
					}
				}
			} else {
				if (column >= 0) {
					for (int r = 0; r < mDnt.RecordCount; r++) {
						GetGridDataNoFilted(r, column, g);
						if (g.text != null && g.text.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0) {
							items.Add(r);
						}
					}
				} else if (column == -1) {
					try {
						int value = int.Parse(filter);
						for (int r = 0; r < mDnt.RecordCount; r++) {
							if (mDnt.GetKey(r) == value) {
								items.Add(r);
							}
						}
					} catch (FormatException) {
					}
				}
			}
			mFiltedItems = items.ToArray();
		}

		public override int RowCount {
			get {
				return mFiltedItems==null?mDnt.RecordCount:mFiltedItems.Length;
			}
		}

		public override int ColumnCount {
			get { return mDnt.FieldCount; }
		}

		public override void GetGridData(int row, int column, Grid grid) {
			if (mFiltedItems != null) {
				row = mFiltedItems[row];
			}
			GetGridDataNoFilted(row, column, grid);
		}

		private void GetGridDataNoFilted(int row, int column, Grid grid) {
			DntField field = mDnt.GetField(column);
			int c = 0;
			if (field.uistring || showAsUIString[column]) {
				string s = Util.FindUIString(((int)mDnt[row, column]));
				if (s != null && field.paramsIndex>=0) {
					string paramsStr = (string)mDnt[row, field.paramsIndex];

					string[] nameParams = Util.parseParams3(paramsStr, out c);
					try {
						s = string.Format(s, nameParams);
					} catch (FormatException) { }
				}
				grid.text = s;
				if (grid.text == null) {
					grid.backgroudColor = Color.Crimson;
					grid.text = "#uis:"+(int)mDnt[row, column];
				}
			} else if (field.uiparams) {
				grid.text = "";
				string[] nameParams = Util.parseParams3(mDnt[row, column].ToString(), out c);
				for (int i=0; i<c; i++) {
					if (i>0)
						grid.text += ",";
					grid.text += nameParams[i];
				}
			} else if (field.fileNameId) {
				grid.text = Util.GetFileName(((int)mDnt[row, column]));
				if (grid.text == null) {
					grid.backgroudColor = Color.Violet;
					grid.text = "#file:"+(int)mDnt[row, column];
				}
			} else
				grid.text = mDnt[row, column].ToString();
			if (grid.text == null) {
				grid.text = "";
			}
		}

		public override void GetRowHeader(int row, Grid grid) {
			if (mFiltedItems != null) {
				row = mFiltedItems[row];
			}
			grid.text = mDnt.GetKey(row).ToString();
		}

		public override void GetColumnHeader(int column, Grid grid) {
			grid.text = mDnt.GetField(column).name+"\n"+ column+".("+mDnt.GetField(column).type+")";
		}

		public override void GetTopLeft(Grid grid) {
			grid.text = "_Key";
		}

		public void Clear() {
			mDnt.Clear();
		}
	}


}
